package liuzy.mvc.core;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import liuzy.mvc.core.annotation.Action;
import liuzy.mvc.core.annotation.Batis;
import liuzy.mvc.core.annotation.Impl;
import liuzy.mvc.core.annotation.Inject;
import liuzy.mvc.core.annotation.Service;
import liuzy.mvc.core.util.Util;

/**
 * Bean工厂
 * 
 * @author liuzy
 * @version 2015年5月13日
 */
public class BeanFactory {
	
	/** classpath下所有的Java类 */
	public static Set<Class<?>> allClasses = null;
	
    /** Bean仓库 */
    private static final Map<Class<?>, Object> beanMap = new HashMap<Class<?>, Object>();
    
    private BeanFactory() {}
 
    public static void load() {
        try {
        	allClasses = ClassScanner.scanner();
        	for (Class<?> cls : allClasses) {
    			if (cls.isAnnotationPresent(Action.class)) {
    				beanMap.put(cls, (Object) cls.newInstance());
    			} else if (cls.isAnnotationPresent(Service.class)) {
    				beanMap.put(cls, (Object) cls.newInstance());
    			} else if (cls.isAnnotationPresent(Batis.class)) {
    				beanMap.put(cls, (Object) new MapperProxyFactory<>(cls).newInstance());
    			}
    		}
        } catch (InstantiationException e1) {
            e1.printStackTrace();
        } catch (IllegalAccessException e2) {
            e2.printStackTrace();
        }
    }
    
    /**
     * 注解注入
     */
    public static void ioc() {
		try {
			for (Map.Entry<Class<?>, Object> beanEntry : beanMap.entrySet()) {
				// 获取 Bean 类与 Bean 实例
				Class<?> beanClass = beanEntry.getKey();
				Object beanInstance = beanEntry.getValue();
				// 获取 Bean 类中所有的字段（不包括父类中的方法）
				Field[] beanFields = beanClass.getDeclaredFields();
				if (beanFields != null) {
					// 遍历所有的 Bean 字段
					for (Field beanField : beanFields) {
						// 判断当前 Bean 字段是否带有 @Inject 注解
						if (beanField.isAnnotationPresent(Inject.class)) {
							// 获取 Bean 字段对应的接口
							Class<?> interfaceClass = beanField.getType();
							// 判断接口上是否标注了 @Impl 注解
							Class<?> implClass = null;
							if (interfaceClass.isAnnotationPresent(Impl.class)) {
								// 获取强制指定的实现类
								implClass = interfaceClass.getAnnotation(Impl.class).value();
							} else if(interfaceClass.isAnnotationPresent(Service.class)) {
								implClass = interfaceClass;
							} else if(interfaceClass.isAnnotationPresent(Batis.class)) {
								implClass = interfaceClass;
							} else {
								// 寻找接口所有的实现类
								List<Class<?>> implClassList = new ArrayList<>();
								for (Class<?> cls : allClasses) {
					    			if (Util.isImpl(cls, interfaceClass))
					    				implClassList.add(cls);
					    			}
								if (implClassList.size() > 0) {
									// 获取第一个实现类
									implClass = implClassList.get(0);
								}
							}
							// 若存在实现类，则执行以下代码
							if (implClass != null) {
								// 从 Bean Map 中获取该实现类对应的实现类实例
								Object implInstance = beanMap.get(implClass);
								// 设置该 Bean 字段的值
								if (implInstance != null) {
									beanField.setAccessible(true); // 取消类型安全检测（可提高反射性能）
									beanField.set(beanInstance, implInstance);
								}
							}
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
    public static Map<Class<?>, Object> getBeanMap() {
        return beanMap;
    }
 
    @SuppressWarnings("unchecked")
    public static <T> T getBean(Class<T> cls) {
        return (T) beanMap.get(cls);
    }
    
    public static void showBeans() {
    	int count = 1;
    	for (Class<?> clazz : beanMap.keySet()) {
			System.out.println("Bean" + count++ + ":" + clazz.getName());
		}
    }

}